package tcln.gxtx.client.utils.store;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.extjs.gxt.ui.client.core.FastMap;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.store.Store;
import com.extjs.gxt.ui.client.widget.grid.GridView;

/**
 * Implementation for {@link RecordUpdater} which updates directly to the modified model. When
 * {@link #updateRecord(Store, ModelData, String, Object)} is called, the change is stored temporarily to an internal
 * map. On invoking {@link #commitChanges(Store, boolean)}, all changes are updated to modified models.
 * <p>
 * <b>Remark</b>: This implementation should only be used when a refresh will be performed somewhere after all changes
 * are committed. An example of this case is the update of a treegrid before applying filters.
 * 
 * @param <M>
 *            model data type.
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public class ModelTargetedRecordUpdater<M extends ModelData> implements RecordUpdater<M> {
    private Map<M, Map<String, Object>> recordUpdateMap = new LinkedHashMap<M, Map<String, Object>>();

    ModelTargetedRecordUpdater() {
        // to hide
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setGridView(GridView gridView) {
        // no gridview is needed

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setStore(Store<M> store) {
        // because there is no update on store, don't need to store this object

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void commitChanges(boolean silent) {
        for (Entry<M, Map<String, Object>> entry : recordUpdateMap.entrySet()) {
            M modifiedModel = entry.getKey();
            Map<String, Object> updatedValueMap = entry.getValue();
            for (Entry<String, Object> updatedEntry : updatedValueMap.entrySet()) {
                modifiedModel.set(updatedEntry.getKey(), updatedEntry.getValue());
            }
        }
        recordUpdateMap.clear();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void finishUpdating() {
        // by default, does nothing because everything was done in 'updateRecord'.
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void updateRecord(M modifiedModel, String property, Object newValue) {
        Map<String, Object> updatedValueMap = recordUpdateMap.get(modifiedModel);
        if (updatedValueMap == null) {
            updatedValueMap = new FastMap<Object>();
            recordUpdateMap.put(modifiedModel, updatedValueMap);
        }
        updatedValueMap.put(property, newValue);
    }
}
